package com.px.user.controller;

import com.google.common.collect.ImmutableMap;
import com.px.common.core.RespCode;
import com.px.common.core.RespException;
import com.px.common.core.Response;
import com.px.common.util.JsonUtil;
import com.px.user.entity.*;
import com.px.user.mapper.*;
import com.px.user.model.*;
import com.px.user.service.CDNService;
import com.px.user.service.RoomService;
import com.px.user.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.Authorization;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.Min;
import java.math.BigDecimal;
import java.security.Principal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Slf4j
@Validated
@RestController
@RequestMapping("/room")
@Api(value = "房间管理", tags = {"房间管理"})
public class RoomController {

    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private VoteMapper voteMapper;

    @Autowired
    private RoomService roomService;

    @Autowired
    private RewardMapper rewardMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private CDNService cdnService;

    @Autowired
    private ConstTMapper constTMapper;

    @PostMapping
    @PreAuthorize("hasAnyAuthority('ADMIN')")
    @ApiOperation(value = "管理员-创建房间", authorizations = {@Authorization(value = "token")}, tags = {"房间"})
    public Response<Long> create(
            @Validated(ActionModel.Insert.class) @RequestBody Room room, Principal principal) {
        room.setCreatorId(Long.valueOf(principal.getName()));

        roomMapper.insert(room);

        return Response.success(room.getId());
    }

    @PutMapping
    @PreAuthorize("hasAnyAuthority('ADMIN', 'ROOMADMIN', 'TEACHER')")
    @ApiOperation(value = "更新房间", authorizations = {@Authorization(value = "token")}, tags = {"房间"})
    public Response<Long> update(
            @Validated(ActionModel.Update.class) @RequestBody Room room, Authentication authentication) {
        Long id = room.getId();
        Collection roles = authentication.getAuthorities();
        SimpleGrantedAuthority admin = new SimpleGrantedAuthority("ADMIN");
        SimpleGrantedAuthority roomAdmin = new SimpleGrantedAuthority("ROOMADMIN");
        SimpleGrantedAuthority teacher = new SimpleGrantedAuthority("TEACHER");
        String userId = authentication.getName();

        if (roles.contains(admin)) {
        } else if (roles.contains(roomAdmin)) {
            if (roomMapper.findByAdminId(Room.builder().id(id).adminId(room.getAdminId()).build()) == null)
                return Response.fail(RespCode.PARA_ERROR, null);
        } else if (roles.contains(teacher)) {
            if (courseMapper.currentTeacherCheck(
                    ImmutableMap.of("teacherId", userId,
                            "roomId", id)) == null)
                return Response.fail(RespCode.PARA_ERROR, null);
            room.setAdminId(null);
        }

        if (room.getVoteContent() != null) {
            voteMapper.delete(id);
            room.setUp(0);
            room.setDown(0);
            room.setFlat(0);
        } else {
            room.setUp(null);
            room.setDown(null);
            room.setFlat(null);
        }

        roomMapper.update(room);
        log.info(userId + " update room info: " + JsonUtil.toJson(room));
        return Response.success(room.getId());
    }

    @GetMapping("/list")
    @ApiOperation(value = "房间列表", notes = "游客使用", tags = {"房间"})
    public Response<PagingResp<Room>> roomAllGet(
            @ApiParam(value = "页码", example = "0") @RequestParam(value = "page", required = false, defaultValue = "0") @Min(0) Integer page,
            @ApiParam(value = "返回数量", example = "10") @RequestParam(value = "size", required = false, defaultValue = "10") @Min(1) Integer limit) {
        Room qRoom = Room.builder().startIndex(page * limit).limit(limit).build();
        List<Room> rooms = roomMapper.paging(qRoom);
        return Response.success(PagingResp.<Room>builder()
                .items(rooms).itemCount(roomMapper.pagingCount(qRoom)).build());
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "房间详情", notes = "游客使用", tags = {"房间"})
    public Response<Room> roomGet(
            @ApiParam(value = "房间ID", example = "4") @PathVariable("id") Long id,
            @ApiParam(value = "截止时间", example = "1566805792293") @RequestParam("startTime") Long startTime) {
        if (id == null)
            return Response.fail(RespCode.PARA_ERROR, null);
        Room room = roomMapper.findById(id);
        if (room == null)
            return Response.fail(RespCode.NOT_FOUND, null);
        List<Course> courses = courseMapper.findByRoomId(Course.builder()
                .qroomId(id)
                .qend(startTime == null ? null : new Timestamp(startTime))
                .build());
        courses.forEach(c -> c.setRoomIds(c.json2roomIds(c.getRoomIds())));
        room.setCourses(courses);
        room.setGg(constTMapper.findByCode("GG").getValue());
        return Response.success(room);
    }

    @DeleteMapping("/{id}")
    @ApiOperation(value = "房间删除", authorizations = {@Authorization(value = "token")}, tags = {"房间"})
    @PreAuthorize("hasAnyAuthority('ADMIN')")
    public Response roomDelete(@ApiParam(value = "房间ID", example = "4") @PathVariable("id") Long id) {
        roomMapper.delete(id);
//        roomPaging.deleteById(id);
        return Response.success(null);
    }

    @PostMapping("/vote")
    @ApiOperation(value = "投票", authorizations = {@Authorization(value = "token")}, notes = "登录后使用", tags = {"投票"})
    public Response<Vote> votePost(
            @Validated(ActionModel.Insert.class) @RequestBody Vote vote, Principal principal) {
        if (vote.getUpdown() == null || vote.getRoomId() == null)
            return Response.fail(RespCode.PARA_ERROR, null);
        Vote preVote = voteMapper.findByUserId(
                ImmutableMap.of("userId", principal.getName(), "roomId", vote.getRoomId()));
        if (preVote != null) {
            long preTime = preVote.getCreateTime().getTime() / 1000;
            long now = new Date().getTime() / 1000;
            if (now - preTime < 0 || now - preTime < TimeUnit.HOURS.toSeconds(3))
                return Response.fail(RespCode.VOTE_FORBIDDEN, null);
        }

        vote.setUserId(Long.valueOf(principal.getName()));
        roomService.updateVote(vote);
        return Response.success(roomService.voteGet(vote.getRoomId()));
    }

    @PostMapping("/check_push")
    @ApiOperation(value = "推流检查", authorizations = {@Authorization(value = "token")}, notes = "讲师使用")
    public Response pushCheckPost(@ApiParam(value = "用户ID", example = "4") @RequestParam("id") String id,
                                  Principal principal) {
        if (!id.equals(principal.getName()))
            return Response.fail(RespCode.FORBIDDEN, null);

        if (courseMapper.pushCheck(Long.valueOf(principal.getName())) == null)
            return Response.fail(RespCode.FORBIDDEN, null);
        return Response.success(null);
    }

    @GetMapping("/reward")
    @ApiOperation(value = "礼物列表", authorizations = {@Authorization(value = "token")}, notes = "登录使用", tags = {"礼物"})
    public Response<List<Reward>> rewardGet() {
        return Response.success(rewardMapper.findAll());
    }

    @PostMapping("/reward")
    @ApiOperation(value = "用户打赏礼物", authorizations = {@Authorization(value = "token")}, notes = "客户使用", tags = {"礼物"})
    public Response userRewardPost(
            @Validated(ActionModel.Insert.class) @RequestBody RewardHis rewardHis, Principal principal) {
        Long fromUserId = Long.valueOf(principal.getName());
        if (fromUserId.equals(rewardHis.getToUserId()))
            return Response.fail(RespCode.PARA_ERROR, "不能给自己送礼物");

        if (courseMapper.currentTeacherCheck(
                ImmutableMap.of("teacherId", rewardHis.getToUserId(),
                        "roomId", rewardHis.getRoomId())) == null)
            return Response.fail(RespCode.PARA_ERROR, null);

        rewardHis.setFromUserId(fromUserId);
        roomService.userReward(rewardHis);
        return Response.success(rewardHis.getId());
    }

    @GetMapping("/rewardRank/{id}")
    @ApiOperation(value = "房间礼物排名", notes = "客户使用", tags = {"礼物"})
    public Response<List<RewardRank>> roomRewardRankGet(
            @ApiParam(value = "房间ID", example = "4") @PathVariable("id") Long id,
            @ApiParam(value = "开始：从0开始", example = "0") @RequestParam("page") int start,
            @ApiParam(value = "结束：-1表示到结尾", example = "10") @RequestParam("size") int end) {
        List<RewardRank> rewardRanks = roomService.getUserRewardRank(id, start, end);
        if (rewardRanks.size() == 0)
            return Response.success(null);
        List<Long> ids = new ArrayList<>();
        rewardRanks.forEach(r -> ids.add(r.getUserId()));
        Map<Long, String> avatars = userService.userAvatars(ids);
        rewardRanks.forEach(r -> r.setAvatar(avatars.get(r.getUserId())));
        return Response.success(rewardRanks);
    }

    /**
     * 发红包
     * @param redPack
     * @param principal
     * @return
     */
    @PostMapping("/redPack")
    @ApiOperation(value = "发红包", authorizations = {@Authorization(value = "token")}, tags = {"红包"})
    public Response sendRpPost(@Validated(ActionModel.Insert.class) @RequestBody RedPack redPack, Principal principal) {
        if (redPack.getRoomId() == null || redPack.getMoney() == null ||
                redPack.getMoney().compareTo(BigDecimal.valueOf(0)) <= 0)
            return Response.fail(RespCode.PARA_ERROR, null);
        if (redPack.getMoney().compareTo(BigDecimal.valueOf(0.1 * redPack.getAmount())) < 0)
            return Response.fail(RespCode.MIN_DIME, null);

        redPack.setMoney(redPack.getMoney().setScale(1, BigDecimal.ROUND_DOWN));
        redPack.setCreatorId(Long.valueOf(principal.getName()));
        redPack.setCategory(RedPackCategory.RANDOM.getStatus());
        return Response.success(userService.sendRp(Long.valueOf(principal.getName()), redPack));
    }

    @GetMapping("/redPack/{id}")
    @ApiOperation(value = "发红包列表", authorizations = {@Authorization(value = "token")}, notes = "客户使用", tags = {"红包"})
    public Response<List<RedPack>> sendRpGet(@ApiParam(value = "房间ID", example = "4") @PathVariable("id") Long id) {
        List<RedPack> redPacks = userService.roomRpList(id);
        return Response.success(redPacks);
    }

    /**
     * 普通用户抢红包
     * @param id
     * @param redPackGrab
     * @param principal
     * @return
     */
    @PostMapping("/grabRp/{id}")
    @ApiOperation(value = "抢红包", authorizations = {@Authorization(value = "token")}, notes = "客户使用", tags = {"红包"})
    public Response<BigDecimal> grabRpPost(
            @ApiParam(value = "房间ID", example = "4") @PathVariable("id") Long id,
            @Validated(ActionModel.Insert.class) @RequestBody RedPackGrab redPackGrab, Principal principal)
            throws IllegalAccessException
    {
        if (redPackGrab.getRedPackId() == null)
            return Response.fail(RespCode.PARA_ERROR, null);

        BigDecimal money;
        try {
            money = userService.grabRp(
                    id, redPackGrab.getFromUserId(), Long.valueOf(principal.getName()), redPackGrab.getRedPackId());
        } catch (RespException e) {
            return Response.fail(e);
        }
        return Response.success(money);
    }

    @PostMapping("/upToken")
    @PreAuthorize("hasAnyAuthority('ADMIN', 'ROOMADMIN', 'TEACHER')")
    @ApiOperation(value = "上传token", authorizations = {@Authorization(value = "token")}, tags = {"视频"})
    public Response<UpTokenModel> upTokenGet() {
        return Response.success(cdnService.qiniuUpToken());
    }

    @PostMapping("/video")
    @PreAuthorize("hasAnyAuthority('ADMIN', 'ROOMADMIN', 'TEACHER')")
    @ApiOperation(value = "视频上传", authorizations = {@Authorization(value = "token")}, tags = {"视频"})
    public Response videoPost(
            @Validated(ActionModel.Insert.class) @RequestBody TeacherVideo teacherVideo, Principal principal) {
        teacherVideo.setCreatorId(Long.valueOf(principal.getName()));
        roomMapper.insertVideo(teacherVideo);
        return Response.success(null);
    }

    @GetMapping("/video/{id}")
    @ApiOperation(value = "视频列表", tags = {"视频"})
    public Response<List<TeacherVideo>> videoGet(@ApiParam(value = "讲师ID", example = "4") @PathVariable("id") Long id) {
        return Response.success(roomMapper.findVideoByCreatorId(id));
    }

    @PutMapping("/video")
    @PreAuthorize("hasAnyAuthority('ADMIN', 'ROOMADMIN', 'TEACHER')")
    @ApiOperation(value = "视频更新", authorizations = {@Authorization(value = "token")}, tags = {"视频"})
    public Response videoPut(
            @Validated(ActionModel.Update.class) @RequestBody TeacherVideo teacherVideo, Principal principal) {
        if (teacherVideo.getId() == null)
            return Response.fail(RespCode.PARA_ERROR, null);
        teacherVideo.setCreatorId(Long.valueOf(principal.getName()));
        roomMapper.updateVideo(teacherVideo);
        return Response.success(null);
    }

    @DeleteMapping("/video/{id}")
    @PreAuthorize("hasAnyAuthority('ADMIN', 'ROOMADMIN', 'TEACHER')")
    @ApiOperation(value = "视频删除", authorizations = {@Authorization(value = "token")}, tags = {"视频"})
    public Response videoDelete(@ApiParam(value = "视频ID", example = "4") @PathVariable("id") Integer id,
                                Authentication authentication) {

        Collection roles = authentication.getAuthorities();
        SimpleGrantedAuthority admin = new SimpleGrantedAuthority("ADMIN");
        if (roles.contains(admin))
            roomMapper.deleteVideo(id);
        else
            roomMapper.deleteVideoByCreatorId(ImmutableMap.of("id", id, "creatorId", authentication.getName()));
        return Response.success(null);
    }

    @GetMapping("/users")
    @ApiOperation(value = "聊天用户列表", tags = {"聊天"})
    public Response<List<Map>> chatUserGet(
            @ApiParam(value = "房间ID", example = "4") @RequestParam("id") Long id,
            @ApiParam(value = "数量", example = "4") @RequestParam(value = "limit", required = false) Integer limit) {
        if (limit == null) limit = 10;
        return Response.success(roomService.chatUser(id, limit));
    }
}
